{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "7a5c2153",
   "metadata": {},
   "source": [
    "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langchain-ai/langchain-academy/blob/main/module-4/research-assistant.ipynb) [![Open in LangChain Academy](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66e9eba12c7b7688aa3dbb5e_LCA-badge-green.svg)](https://academy.langchain.com/courses/take/intro-to-langgraph/lessons/58239974-lesson-4-research-assistant)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "e0a5763f-5f45-4b8f-b3e2-480f46c5721b",
   "metadata": {},
   "source": [
    "# Trading Assistant\n",
    "\n",
    "## Overview\n",
    "* Modified the research assistant model to fit a trading scheme\n",
    "* Add in Analysts Team with Human-in-the-loop\n",
    "* Add in Researcher Team - Two agents that debate based on analysis report\n",
    "* Add in Risk & Fund Management to qualify and quantify trader's decision, finalizing it\n",
    "\n",
    "## Next Steps\n",
    "* Include table summaries\n",
    "* Add in summarizing for researcher debate to reduce token usage (although note full transcript currently works as long running summary)\n",
    "* Test model with paper trading\n",
    "* Include tools to calculate Market Stats"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "99a1c01d-87e1-4723-b83e-ebcf937fe914",
   "metadata": {},
   "source": [
    "## Setup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "ba917800-10e4-4e2a-8e9e-30893b731e97",
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "OPENAI_API_KEY:  ········\n"
     ]
    }
   ],
   "source": [
    "import os, getpass\n",
    "\n",
    "def _set_env(var: str):\n",
    "    if not os.environ.get(var):\n",
    "        os.environ[var] = getpass.getpass(f\"{var}: \")\n",
    "\n",
    "_set_env(\"OPENAI_API_KEY\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "afe9ff57-0826-4669-b88b-4d0501a509f5",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0) "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3419257b-2c6b-4d68-ae38-4a266cc02982",
   "metadata": {},
   "source": [
    "We'll use [LangSmith](https://docs.smith.langchain.com/) for [tracing](https://docs.smith.langchain.com/concepts/tracing)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "5102cf2e-0ca9-465b-9499-67abb8132e5d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "LANGCHAIN_API_KEY:  ········\n"
     ]
    }
   ],
   "source": [
    "_set_env(\"LANGCHAIN_API_KEY\")\n",
    "os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n",
    "os.environ[\"LANGCHAIN_PROJECT\"] = \"langchain-academy\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f8fe5d93-e353-44bb-be3e-434654bcb7ea",
   "metadata": {},
   "source": [
    "## Generate Analysts: Human-In-The-Loop\n",
    "\n",
    "Create analysts and review them using human-in-the-loop."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "1eee8e60-e548-49b1-88ec-a4f3aef2174e",
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "from typing_extensions import TypedDict\n",
    "from pydantic import BaseModel, Field\n",
    "\n",
    "class Analyst(BaseModel):\n",
    "    affiliation: str = Field(\n",
    "        description=\"Primary affiliation of the analyst.\",\n",
    "    )\n",
    "    name: str = Field(\n",
    "        description=\"Name of the analyst.\"\n",
    "    )\n",
    "    role: str = Field(\n",
    "        description=\"Role of the analyst in the context of the topic.\",\n",
    "    )\n",
    "    description: str = Field(\n",
    "        description=\"Description of the analyst focus, concerns, and motives.\",\n",
    "    )\n",
    "    @property\n",
    "    def persona(self) -> str:\n",
    "        return f\"Name: {self.name}\\nRole: {self.role}\\nAffiliation: {self.affiliation}\\nDescription: {self.description}\\n\"\n",
    "\n",
    "class Perspectives(BaseModel):\n",
    "    analysts: List[Analyst] = Field(\n",
    "        description=\"Comprehensive list of analysts with their roles and affiliations.\",\n",
    "    )\n",
    "\n",
    "class GenerateAnalystsState(TypedDict):\n",
    "    topic: str # Research topic\n",
    "    max_analysts: int # Number of analysts\n",
    "    human_analyst_feedback: str # Human feedback\n",
    "    analysts: List[Analyst] # Analyst asking questions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "fd088ff5-4c75-412c-85f0-04afd0900bfc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import Image, display\n",
    "from langgraph.graph import START, END, StateGraph\n",
    "from langgraph.checkpoint.memory import MemorySaver\n",
    "from langchain_core.messages import AIMessage, HumanMessage, SystemMessage\n",
    "\n",
    "analyst_instructions=\"\"\"You are tasked with creating a set of AI analyst personas. Follow these instructions carefully:\n",
    "\n",
    "1. The analysts will be be analyzing the {topic} stock market trends.\n",
    "\n",
    "2. Examine any editorial feedback that has been optionally provided to guide creation of the analysts: \n",
    "        \n",
    "{human_analyst_feedback}\n",
    "\n",
    "3. Here are the main analysis themes\n",
    "- Market Analyst: Analyze market trends using technical indications\n",
    "- Social Media Sentiment Analyst: Analyze social media sentiment trends\n",
    "- News Analyst: Analyze global economic trends affecting markets\n",
    "- Fundamentals Analyst: Analyze and evaluate company financials and stock performance\n",
    "\n",
    "4. Assign one analyst to each theme. Ensure they specialize in this theme for the {topic} stock\"\"\"\n",
    "\n",
    "def create_analysts(state: GenerateAnalystsState):\n",
    "    \n",
    "    \"\"\" Create analysts \"\"\"\n",
    "    \n",
    "    topic=state['topic']\n",
    "    max_analysts=state['max_analysts']\n",
    "    human_analyst_feedback=state.get('human_analyst_feedback', '')\n",
    "        \n",
    "    # Enforce structured output\n",
    "    structured_llm = llm.with_structured_output(Perspectives)\n",
    "\n",
    "    # System message\n",
    "    system_message = analyst_instructions.format(topic=topic,\n",
    "                                                            human_analyst_feedback=human_analyst_feedback, \n",
    "                                                            max_analysts=max_analysts)\n",
    "\n",
    "    # Generate question \n",
    "    analysts = structured_llm.invoke([SystemMessage(content=system_message)]+[HumanMessage(content=\"Generate the set of analysts.\")])\n",
    "    \n",
    "    # Write the list of analysis to state\n",
    "    return {\"analysts\": analysts.analysts}\n",
    "\n",
    "def human_feedback(state: GenerateAnalystsState):\n",
    "    \"\"\" No-op node that should be interrupted on \"\"\"\n",
    "    pass\n",
    "\n",
    "def should_continue(state: GenerateAnalystsState):\n",
    "    \"\"\" Return the next node to execute \"\"\"\n",
    "\n",
    "    # Check if human feedback\n",
    "    human_analyst_feedback=state.get('human_analyst_feedback', None)\n",
    "    if human_analyst_feedback:\n",
    "        return \"create_analysts\"\n",
    "    \n",
    "    # Otherwise end\n",
    "    return END\n",
    "\n",
    "# Add nodes and edges \n",
    "builder = StateGraph(GenerateAnalystsState)\n",
    "builder.add_node(\"create_analysts\", create_analysts)\n",
    "builder.add_node(\"human_feedback\", human_feedback)\n",
    "builder.add_edge(START, \"create_analysts\")\n",
    "builder.add_edge(\"create_analysts\", \"human_feedback\")\n",
    "builder.add_conditional_edges(\"human_feedback\", should_continue, [\"create_analysts\", END])\n",
    "\n",
    "# Compile\n",
    "memory = MemorySaver()\n",
    "graph = builder.compile(interrupt_before=['human_feedback'], checkpointer=memory)\n",
    "\n",
    "# View\n",
    "display(Image(graph.get_graph(xray=1).draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "6c22cb05-c436-4358-8f7a-72d722f9b5cc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Name: Jordan Lee\n",
      "Affiliation: MarketWatch\n",
      "Role: Market Analyst\n",
      "Description: Jordan specializes in analyzing market trends for AAPL using technical indicators such as moving averages, RSI, and MACD. With a keen eye for chart patterns, Jordan provides insights on potential price movements and market entry points.\n",
      "--------------------------------------------------\n",
      "Name: Samantha Chen\n",
      "Affiliation: Sentiment Analysis Group\n",
      "Role: Social Media Sentiment Analyst\n",
      "Description: Samantha focuses on analyzing social media sentiment surrounding AAPL stock. By leveraging natural language processing tools, she gauges public sentiment from platforms like Twitter and Reddit, providing insights into how social media trends may influence stock performance.\n",
      "--------------------------------------------------\n",
      "Name: Michael Thompson\n",
      "Affiliation: Global Economic Review\n",
      "Role: News Analyst\n",
      "Description: Michael analyzes global economic trends and their impact on AAPL stock. He monitors news events, economic indicators, and geopolitical developments to assess how these factors may affect investor sentiment and stock performance.\n",
      "--------------------------------------------------\n",
      "Name: Emily Rodriguez\n",
      "Affiliation: Financial Insights\n",
      "Role: Fundamentals Analyst\n",
      "Description: Emily specializes in evaluating AAPL's financial health by analyzing earnings reports, revenue growth, profit margins, and other key financial metrics. Her focus is on understanding the company's fundamentals to provide long-term investment insights.\n",
      "--------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "# Input\n",
    "max_analysts = 4 \n",
    "topic = \"AAPL\" #replace with any stock ticker\n",
    "thread = {\"configurable\": {\"thread_id\": \"1\"}}\n",
    "\n",
    "# Run the graph until the first interruption\n",
    "for event in graph.stream({\"topic\":topic,\"max_analysts\":max_analysts,}, thread, stream_mode=\"values\"):\n",
    "    # Review\n",
    "    analysts = event.get('analysts', '')\n",
    "    if analysts:\n",
    "        for analyst in analysts:\n",
    "            print(f\"Name: {analyst.name}\")\n",
    "            print(f\"Affiliation: {analyst.affiliation}\")\n",
    "            print(f\"Role: {analyst.role}\")\n",
    "            print(f\"Description: {analyst.description}\")\n",
    "            print(\"-\" * 50)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "e7e283a8-9b5b-4d47-a628-1ebeeba69471",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('human_feedback',)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Get state and look at next node\n",
    "state = graph.get_state(thread)\n",
    "state.next"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "7405d2ad-4bf1-4d2c-b291-859dc9fdef12",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'configurable': {'thread_id': '1',\n",
       "  'checkpoint_ns': '',\n",
       "  'checkpoint_id': '1f00f2c9-a7a1-6b53-8002-6f05468567d5'}}"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# We now update the state as if we are the human_feedback node\n",
    "graph.update_state(thread, {\"human_analyst_feedback\": \n",
    "                            \"ensure that the news analyst only uses news from the past three weeks\"}, as_node=\"human_feedback\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "45b43a5d-f90f-4d42-88e6-2bdb72af8430",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Name: Jordan Lee\n",
      "Affiliation: MarketWatch\n",
      "Role: Market Analyst\n",
      "Description: Jordan specializes in analyzing market trends for AAPL using technical indicators such as moving averages, RSI, and MACD. With a keen eye for chart patterns, Jordan provides insights on potential price movements and market entry points.\n",
      "--------------------------------------------------\n",
      "Name: Samantha Chen\n",
      "Affiliation: Sentiment Analysis Group\n",
      "Role: Social Media Sentiment Analyst\n",
      "Description: Samantha focuses on analyzing social media sentiment surrounding AAPL stock. By leveraging natural language processing tools, she gauges public sentiment from platforms like Twitter and Reddit, providing insights into how social media trends may influence stock performance.\n",
      "--------------------------------------------------\n",
      "Name: Michael Thompson\n",
      "Affiliation: Global Economic Review\n",
      "Role: News Analyst\n",
      "Description: Michael analyzes global economic trends and their impact on AAPL stock. He monitors news events, economic indicators, and geopolitical developments to assess how these factors may affect investor sentiment and stock performance.\n",
      "--------------------------------------------------\n",
      "Name: Emily Rodriguez\n",
      "Affiliation: Financial Insights\n",
      "Role: Fundamentals Analyst\n",
      "Description: Emily specializes in evaluating AAPL's financial health by analyzing earnings reports, revenue growth, profit margins, and other key financial metrics. Her focus is on understanding the company's fundamentals to provide long-term investment insights.\n",
      "--------------------------------------------------\n",
      "Name: Jordan Lee\n",
      "Affiliation: MarketWatch\n",
      "Role: Market Analyst\n",
      "Description: Jordan specializes in analyzing market trends for AAPL using technical indicators. He focuses on price movements, volume trends, and chart patterns to provide insights into potential future price actions.\n",
      "--------------------------------------------------\n",
      "Name: Maya Chen\n",
      "Affiliation: Sentiment Analysis Co.\n",
      "Role: Social Media Sentiment Analyst\n",
      "Description: Maya tracks social media sentiment around AAPL, analyzing tweets, posts, and comments to gauge public perception and investor sentiment. She uses advanced algorithms to quantify sentiment trends and their potential impact on stock performance.\n",
      "--------------------------------------------------\n",
      "Name: Ethan Patel\n",
      "Affiliation: Global Economic Review\n",
      "Role: News Analyst\n",
      "Description: Ethan examines global economic trends and news that could affect AAPL's stock performance. He focuses on recent developments in trade policies, economic indicators, and major news events from the past three weeks to provide context for market movements.\n",
      "--------------------------------------------------\n",
      "Name: Sophia Martinez\n",
      "Affiliation: Financial Insights Group\n",
      "Role: Fundamentals Analyst\n",
      "Description: Sophia evaluates AAPL's financial health by analyzing quarterly earnings reports, revenue growth, profit margins, and other key financial metrics. She assesses the company's performance relative to its competitors and the overall market.\n",
      "--------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "# Continue the graph execution\n",
    "for event in graph.stream(None, thread, stream_mode=\"values\"):\n",
    "    # Review\n",
    "    analysts = event.get('analysts', '')\n",
    "    if analysts:\n",
    "        for analyst in analysts:\n",
    "            print(f\"Name: {analyst.name}\")\n",
    "            print(f\"Affiliation: {analyst.affiliation}\")\n",
    "            print(f\"Role: {analyst.role}\")\n",
    "            print(f\"Description: {analyst.description}\")\n",
    "            print(\"-\" * 50) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "f014630b-7660-473b-bc54-f6acc0eb17c4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'configurable': {'thread_id': '1',\n",
       "  'checkpoint_ns': '',\n",
       "  'checkpoint_id': '1f00f2c9-d334-6242-8004-a26a05f5d8a1'}}"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# If we are satisfied, then we simply supply no feedback\n",
    "further_feedack = None\n",
    "graph.update_state(thread, {\"human_analyst_feedback\": \n",
    "                            further_feedack}, as_node=\"human_feedback\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "ab034e65-aeee-4723-8d6d-74541b548425",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Continue the graph execution to end\n",
    "for event in graph.stream(None, thread, stream_mode=\"updates\"):\n",
    "    print(\"--Node--\")\n",
    "    node_name = next(iter(event.keys()))\n",
    "    print(node_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "2f204e8a-285c-4e46-8223-a695caec7764",
   "metadata": {},
   "outputs": [],
   "source": [
    "final_state = graph.get_state(thread)\n",
    "analysts = final_state.values.get('analysts')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "59704086-cb3b-42e9-8395-37be6f0d44e9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "final_state.next"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "95717ba3-aa00-48d6-bbb7-5fe4db5919bf",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Name: Jordan Lee\n",
      "Affiliation: MarketWatch\n",
      "Role: Market Analyst\n",
      "Description: Jordan specializes in analyzing market trends for AAPL using technical indicators. He focuses on price movements, volume trends, and chart patterns to provide insights into potential future price actions.\n",
      "--------------------------------------------------\n",
      "Name: Maya Chen\n",
      "Affiliation: Sentiment Analysis Co.\n",
      "Role: Social Media Sentiment Analyst\n",
      "Description: Maya tracks social media sentiment around AAPL, analyzing tweets, posts, and comments to gauge public perception and investor sentiment. She uses advanced algorithms to quantify sentiment trends and their potential impact on stock performance.\n",
      "--------------------------------------------------\n",
      "Name: Ethan Patel\n",
      "Affiliation: Global Economic Review\n",
      "Role: News Analyst\n",
      "Description: Ethan examines global economic trends and news that could affect AAPL's stock performance. He focuses on recent developments in trade policies, economic indicators, and major news events from the past three weeks to provide context for market movements.\n",
      "--------------------------------------------------\n",
      "Name: Sophia Martinez\n",
      "Affiliation: Financial Insights Group\n",
      "Role: Fundamentals Analyst\n",
      "Description: Sophia evaluates AAPL's financial health by analyzing quarterly earnings reports, revenue growth, profit margins, and other key financial metrics. She assesses the company's performance relative to its competitors and the overall market.\n",
      "--------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "for analyst in analysts:\n",
    "    print(f\"Name: {analyst.name}\")\n",
    "    print(f\"Affiliation: {analyst.affiliation}\")\n",
    "    print(f\"Role: {analyst.role}\")\n",
    "    print(f\"Description: {analyst.description}\")\n",
    "    print(\"-\" * 50) "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7d2498e4-20ae-4503-9dd0-a4165132b7a7",
   "metadata": {},
   "source": [
    "## Conduct Interview\n",
    "\n",
    "### Generate Question\n",
    "\n",
    "The analyst will ask questions to the expert."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "e5d5f559-f42e-442b-87cd-dbf0a91abf9c",
   "metadata": {},
   "outputs": [],
   "source": [
    "import operator\n",
    "from typing import  Annotated\n",
    "from langgraph.graph import MessagesState\n",
    "\n",
    "class InterviewState(MessagesState):\n",
    "    max_num_turns: int # Number turns of conversation\n",
    "    context: Annotated[list, operator.add] # Source docs\n",
    "    analyst: Analyst # Analyst asking questions\n",
    "    interview: str # Interview transcript\n",
    "    sections: list # Final key we duplicate in outer state for Send() API\n",
    "\n",
    "class SearchQuery(BaseModel):\n",
    "    search_query: str = Field(None, description=\"Search query for retrieval.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "1c2e71eb-07ad-4bea-aabc-dbaf551408c0",
   "metadata": {},
   "outputs": [],
   "source": [
    "question_instructions = \"\"\"You are an analyst tasked with interviewing an expert to learn about a specific stock's market trends.\n",
    "\n",
    "Your goal is gather key information about the stock, with emphasis on your area of focus.\n",
    "\n",
    "Here is your topic of focus and set of goals: {goals}\n",
    "        \n",
    "Begin by introducing yourself using a name that fits your persona, and then ask your question.\n",
    "\n",
    "Continue to ask questions to drill down and refine your understanding of the topic.\n",
    "        \n",
    "When you are satisfied with your understanding, complete the interview with: \"Thank you so much for your help!\"\n",
    "\n",
    "Remember to stay in character throughout your response, reflecting the persona and goals provided to you.\"\"\"\n",
    "\n",
    "def generate_question(state: InterviewState):\n",
    "    \"\"\" Node to generate a question \"\"\"\n",
    "\n",
    "    # Get state\n",
    "    analyst = state[\"analyst\"]\n",
    "    messages = state[\"messages\"]\n",
    "\n",
    "    # Generate question \n",
    "    system_message = question_instructions.format(goals=analyst.persona)\n",
    "    question = llm.invoke([SystemMessage(content=system_message)]+messages)\n",
    "        \n",
    "    # Write messages to state\n",
    "    return {\"messages\": [question]}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "be2ff33a-6232-4a79-8a82-882a645394f5",
   "metadata": {},
   "source": [
    "### Generate Answer: Parallelization\n",
    "\n",
    "The expert will gather information from multiple sources in parallel to answer questions.\n",
    "\n",
    "For example, we can use:\n",
    "\n",
    "* Specific web sites e.g., via [`WebBaseLoader`](https://python.langchain.com/v0.2/docs/integrations/document_loaders/web_base/)\n",
    "* Indexed documents e.g., via [RAG](https://python.langchain.com/v0.2/docs/tutorials/rag/)\n",
    "* Web search\n",
    "* Wikipedia search\n",
    "\n",
    "You can try different web search tools, like [Tavily](https://tavily.com/)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "606ea95b-e811-4299-8b66-835d4016c338",
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "TAVILY_API_KEY:  ········\n"
     ]
    }
   ],
   "source": [
    "def _set_env(var: str):\n",
    "    if not os.environ.get(var):\n",
    "        os.environ[var] = getpass.getpass(f\"{var}: \")\n",
    "\n",
    "_set_env(\"TAVILY_API_KEY\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "c61ae74a-f838-4e97-8bd5-48ccd15b7789",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Web search tool\n",
    "from langchain_community.tools.tavily_search import TavilySearchResults\n",
    "tavily_search = TavilySearchResults(max_results=3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "2d8f760b-5a1a-4fa9-a014-d3fb02bec51c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Wikipedia search tool\n",
    "from langchain_community.document_loaders import WikipediaLoader"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "06cb1603",
   "metadata": {},
   "source": [
    "Now, we create nodes to search the web and wikipedia.\n",
    "\n",
    "We'll also create a node to answer analyst questions.\n",
    "\n",
    "Finally, we'll create nodes to save the full interview and to write a summary (\"section\") of the interview."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "9c863768-2278-415b-aef1-96fd18c1b1cb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from langchain_core.messages import get_buffer_string\n",
    "\n",
    "# Search query writing\n",
    "search_instructions = SystemMessage(content=f\"\"\"You will be given a conversation between an analyst and an expert. \n",
    "\n",
    "Your goal is to generate a well-structured query for use in retrieval and / or web-search related to the conversation.\n",
    "        \n",
    "First, analyze the full conversation.\n",
    "\n",
    "Pay particular attention to the final question posed by the analyst.\n",
    "\n",
    "Convert this final question into a well-structured web search query\"\"\")\n",
    "\n",
    "def search_web(state: InterviewState):\n",
    "    \n",
    "    \"\"\" Retrieve docs from web search \"\"\"\n",
    "\n",
    "    # Search query\n",
    "    structured_llm = llm.with_structured_output(SearchQuery)\n",
    "    search_query = structured_llm.invoke([search_instructions]+state['messages'])\n",
    "    \n",
    "    # Search\n",
    "    search_docs = tavily_search.invoke(search_query.search_query)\n",
    "\n",
    "     # Format\n",
    "    formatted_search_docs = \"\\n\\n---\\n\\n\".join(\n",
    "        [\n",
    "            f'<Document href=\"{doc[\"url\"]}\"/>\\n{doc[\"content\"]}\\n</Document>'\n",
    "            for doc in search_docs\n",
    "        ]\n",
    "    )\n",
    "\n",
    "    return {\"context\": [formatted_search_docs]} \n",
    "\n",
    "def search_wikipedia(state: InterviewState):\n",
    "    \n",
    "    \"\"\" Retrieve docs from wikipedia \"\"\"\n",
    "\n",
    "    # Search query\n",
    "    structured_llm = llm.with_structured_output(SearchQuery)\n",
    "    search_query = structured_llm.invoke([search_instructions]+state['messages'])\n",
    "    \n",
    "    # Search\n",
    "    search_docs = WikipediaLoader(query=search_query.search_query, \n",
    "                                  load_max_docs=2).load()\n",
    "\n",
    "     # Format\n",
    "    formatted_search_docs = \"\\n\\n---\\n\\n\".join(\n",
    "        [\n",
    "            f'<Document source=\"{doc.metadata[\"source\"]}\" page=\"{doc.metadata.get(\"page\", \"\")}\"/>\\n{doc.page_content}\\n</Document>'\n",
    "            for doc in search_docs\n",
    "        ]\n",
    "    )\n",
    "\n",
    "    return {\"context\": [formatted_search_docs]} \n",
    "\n",
    "answer_instructions = \"\"\"You are an expert being interviewed by an analyst.\n",
    "\n",
    "Here is analyst area of focus: {goals}. \n",
    "        \n",
    "You goal is to answer a question posed by the interviewer.\n",
    "\n",
    "To answer question, use this context:\n",
    "        \n",
    "{context}\n",
    "\n",
    "When answering questions, follow these guidelines:\n",
    "        \n",
    "1. Use only the information provided in the context. \n",
    "        \n",
    "2. Do not introduce external information or make assumptions beyond what is explicitly stated in the context.\n",
    "\n",
    "3. The context contain sources at the topic of each individual document.\n",
    "\n",
    "4. Include these sources your answer next to any relevant statements. For example, for source # 1 use [1]. \n",
    "\n",
    "5. List your sources in order at the bottom of your answer. [1] Source 1, [2] Source 2, etc\n",
    "        \n",
    "6. If the source is: <Document source=\"assistant/docs/llama3_1.pdf\" page=\"7\"/>' then just list: \n",
    "        \n",
    "[1] assistant/docs/llama3_1.pdf, page 7 \n",
    "        \n",
    "And skip the addition of the brackets as well as the Document source preamble in your citation.\"\"\"\n",
    "\n",
    "def generate_answer(state: InterviewState):\n",
    "    \n",
    "    \"\"\" Node to answer a question \"\"\"\n",
    "\n",
    "    # Get state\n",
    "    analyst = state[\"analyst\"]\n",
    "    messages = state[\"messages\"]\n",
    "    context = state[\"context\"]\n",
    "\n",
    "    # Answer question\n",
    "    system_message = answer_instructions.format(goals=analyst.persona, context=context)\n",
    "    answer = llm.invoke([SystemMessage(content=system_message)]+messages)\n",
    "            \n",
    "    # Name the message as coming from the expert\n",
    "    answer.name = \"expert\"\n",
    "    \n",
    "    # Append it to state\n",
    "    return {\"messages\": [answer]}\n",
    "\n",
    "def save_interview(state: InterviewState):\n",
    "    \n",
    "    \"\"\" Save interviews \"\"\"\n",
    "\n",
    "    # Get messages\n",
    "    messages = state[\"messages\"]\n",
    "    \n",
    "    # Convert interview to a string\n",
    "    interview = get_buffer_string(messages)\n",
    "    \n",
    "    # Save to interviews key\n",
    "    return {\"interview\": interview}\n",
    "\n",
    "def route_messages(state: InterviewState, \n",
    "                   name: str = \"expert\"):\n",
    "\n",
    "    \"\"\" Route between question and answer \"\"\"\n",
    "    \n",
    "    # Get messages\n",
    "    messages = state[\"messages\"]\n",
    "    max_num_turns = state.get('max_num_turns',2)\n",
    "\n",
    "    # Check the number of expert answers \n",
    "    num_responses = len(\n",
    "        [m for m in messages if isinstance(m, AIMessage) and m.name == name]\n",
    "    )\n",
    "\n",
    "    # End if expert has answered more than the max turns\n",
    "    if num_responses >= max_num_turns:\n",
    "        return 'save_interview'\n",
    "\n",
    "    # This router is run after each question - answer pair \n",
    "    # Get the last question asked to check if it signals the end of discussion\n",
    "    last_question = messages[-2]\n",
    "    \n",
    "    if \"Thank you so much for your help\" in last_question.content:\n",
    "        return 'save_interview'\n",
    "    return \"ask_question\"\n",
    "\n",
    "section_writer_instructions = \"\"\"You are an expert technical writer. \n",
    "            \n",
    "Your task is to create a short, easily digestible section of a report based on a set of source documents.\n",
    "\n",
    "1. Analyze the content of the source documents: \n",
    "- The name of each source document is at the start of the document, with the <Document tag.\n",
    "        \n",
    "2. Create a report structure using markdown formatting:\n",
    "- Use ## for the section title\n",
    "- Use ### for sub-section headers\n",
    "        \n",
    "3. Write the report following this structure:\n",
    "a. Title (## header)\n",
    "b. Summary (### header)\n",
    "c. Sources (### header)\n",
    "\n",
    "4. Make your title engaging based upon the focus area of the analyst: \n",
    "{focus}\n",
    "\n",
    "5. For the summary section:\n",
    "- Set up summary with general background / context related to the focus area of the analyst\n",
    "- Emphasize the key insights gathered from the interview that are supported by the most evidence\n",
    "- Create a numbered list of source documents, as you use them\n",
    "- Do not mention the names of interviewers or experts\n",
    "- Aim for approximately 400 words maximum\n",
    "- Use numbered sources in your report (e.g., [1], [2]) based on information from source documents\n",
    "        \n",
    "6. In the Sources section:\n",
    "- Include all sources used in your report\n",
    "- Provide full links to relevant websites or specific document paths\n",
    "- Separate each source by a newline. Use two spaces at the end of each line to create a newline in Markdown.\n",
    "- It will look like:\n",
    "\n",
    "### Sources\n",
    "[1] Link or Document name\n",
    "[2] Link or Document name\n",
    "\n",
    "7. Be sure to combine sources. For example this is not correct:\n",
    "\n",
    "[3] https://ai.meta.com/blog/meta-llama-3-1/\n",
    "[4] https://ai.meta.com/blog/meta-llama-3-1/\n",
    "\n",
    "There should be no redundant sources. It should simply be:\n",
    "\n",
    "[3] https://ai.meta.com/blog/meta-llama-3-1/\n",
    "        \n",
    "8. Final review:\n",
    "- Ensure the report follows the required structure\n",
    "- Include no preamble before the title of the report\n",
    "- Check that all guidelines have been followed\"\"\"\n",
    "\n",
    "def write_section(state: InterviewState):\n",
    "\n",
    "    \"\"\" Node to answer a question \"\"\"\n",
    "\n",
    "    # Get state\n",
    "    interview = state[\"interview\"]\n",
    "    context = state[\"context\"]\n",
    "    analyst = state[\"analyst\"]\n",
    "   \n",
    "    # Write section using either the gathered source docs from interview (context) or the interview itself (interview)\n",
    "    system_message = section_writer_instructions.format(focus=analyst.description)\n",
    "    section = llm.invoke([SystemMessage(content=system_message)]+[HumanMessage(content=f\"Use this source to write your section: {context}\")]) \n",
    "                \n",
    "    # Append it to state\n",
    "    return {\"sections\": [section.content]}\n",
    "\n",
    "# Add nodes and edges \n",
    "interview_builder = StateGraph(InterviewState)\n",
    "interview_builder.add_node(\"ask_question\", generate_question)\n",
    "interview_builder.add_node(\"search_web\", search_web)\n",
    "interview_builder.add_node(\"search_wikipedia\", search_wikipedia)\n",
    "interview_builder.add_node(\"answer_question\", generate_answer)\n",
    "interview_builder.add_node(\"save_interview\", save_interview)\n",
    "interview_builder.add_node(\"write_section\", write_section)\n",
    "\n",
    "# Flow\n",
    "interview_builder.add_edge(START, \"ask_question\")\n",
    "interview_builder.add_edge(\"ask_question\", \"search_web\")\n",
    "interview_builder.add_edge(\"ask_question\", \"search_wikipedia\")\n",
    "interview_builder.add_edge(\"search_web\", \"answer_question\")\n",
    "interview_builder.add_edge(\"search_wikipedia\", \"answer_question\")\n",
    "interview_builder.add_conditional_edges(\"answer_question\", route_messages,['ask_question','save_interview'])\n",
    "interview_builder.add_edge(\"save_interview\", \"write_section\")\n",
    "interview_builder.add_edge(\"write_section\", END)\n",
    "\n",
    "# Interview \n",
    "memory = MemorySaver()\n",
    "interview_graph = interview_builder.compile(checkpointer=memory).with_config(run_name=\"Conduct Interviews\")\n",
    "\n",
    "# View\n",
    "display(Image(interview_graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "50f382f1-6e93-48d0-a44a-1094d26ccb1e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Analyst(affiliation='MarketWatch', name='Jordan Lee', role='Market Analyst', description='Jordan specializes in analyzing market trends for AAPL using technical indicators. He focuses on price movements, volume trends, and chart patterns to provide insights into potential future price actions.')"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Pick one analyst\n",
    "analysts[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "b2242d4e-8430-4de9-8cf7-3ad2f9a22b28",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "## Analyzing AAPL: Insights from Technical Indicators\n",
       "\n",
       "### Summary\n",
       "Apple Inc. (AAPL) has been a focal point for investors and analysts alike, particularly in the realm of technical analysis. This approach utilizes various indicators to assess price movements, volume trends, and chart patterns, providing insights into potential future price actions. Recent evaluations of AAPL's technical indicators reveal a mixed outlook, with several indicators suggesting both buy and sell signals.\n",
       "\n",
       "Key indicators such as the Relative Strength Index (RSI), Moving Averages, and the Moving Average Convergence Divergence (MACD) are critical in determining the stock's momentum. As of the latest analysis, the RSI stands at approximately 52.58, indicating a neutral position, while the MACD shows a slight bullish signal at 0.7, suggesting potential upward momentum [1]. However, other indicators, such as the Average Directional Index (ADX) at 42.67, also indicate a buy signal, reflecting strong trend strength [1].\n",
       "\n",
       "Moving averages play a crucial role in assessing both short-term and long-term trends. The 50-day and 200-day moving averages are particularly significant, with the current analysis showing a neutral stance overall, with 6 buy and 6 sell signals [1]. This balance suggests that while there are opportunities for upward movement, caution is warranted due to the presence of sell signals from other indicators, such as the Commodity Channel Index (CCI) and the Ultimate Oscillator [1].\n",
       "\n",
       "Moreover, the Awesome Oscillator and Momentum indicators also reflect a neutral to slightly bearish sentiment, with values of -18.51 and -18.90, respectively [2]. This indicates that while there may be short-term buying opportunities, the overall market sentiment remains cautious.\n",
       "\n",
       "In summary, AAPL's technical indicators present a complex picture. Investors should consider the mixed signals from various indicators, balancing the potential for upward movement against the risks indicated by sell signals. A prudent approach would involve waiting for clearer consolidation patterns before making significant investment decisions.\n",
       "\n",
       "### Sources\n",
       "[1] https://www.investing.com/equities/apple-computer-inc-technical/  \n",
       "[2] https://www.tradingview.com/symbols/NASDAQ-AAPL/technicals/  \n",
       "[3] https://www.chartmill.com/stock/quote/AAPL/technical-analysis  \n",
       "[4] https://altindex.com/ticker/aapl/technical-analysis  "
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.display import Markdown\n",
    "messages = [HumanMessage(f\"So you said you were analyzing the {topic} stock?\")]\n",
    "thread = {\"configurable\": {\"thread_id\": \"1\"}}\n",
    "interview = interview_graph.invoke({\"analyst\": analysts[0], \"messages\": messages, \"max_num_turns\": 2}, thread)\n",
    "Markdown(interview['sections'][0])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3b739e87-68bb-4e96-a86a-704e84240a6c",
   "metadata": {},
   "source": [
    "### Parallelze interviews: Map-Reduce\n",
    "\n",
    "We parallelize the interviews via the `Send()` API, a map step.\n",
    "\n",
    "We combine them into the report body in a reduce step.\n",
    "\n",
    "### Finalize\n",
    "\n",
    "We add a final step to write an intro and conclusion to the final report."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "6a0042f9-5b9f-441a-9e8d-7d8189f44140",
   "metadata": {},
   "outputs": [],
   "source": [
    "import operator\n",
    "from typing import List, Annotated\n",
    "from typing_extensions import TypedDict\n",
    "\n",
    "class ResearchGraphState(TypedDict):\n",
    "    topic: str # Research topic\n",
    "    max_analysts: int # Number of analysts\n",
    "    human_analyst_feedback: str # Human feedback\n",
    "    analysts: List[Analyst] # Analyst asking questions\n",
    "    sections: Annotated[list, operator.add] # Send() API key\n",
    "    introduction: str # Introduction for the final report\n",
    "    content: str # Content for the final report\n",
    "    conclusion: str # Conclusion for the final report\n",
    "    final_report: str # Final report"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "c2224592-d2ff-469d-97bd-928809f896d7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from langgraph.constants import Send\n",
    "\n",
    "def initiate_all_interviews(state: ResearchGraphState):\n",
    "    \"\"\" This is the \"map\" step where we run each interview sub-graph using Send API \"\"\"    \n",
    "\n",
    "    # Check if human feedback\n",
    "    human_analyst_feedback=state.get('human_analyst_feedback')\n",
    "    if human_analyst_feedback:\n",
    "        # Return to create_analysts\n",
    "        return \"create_analysts\"\n",
    "\n",
    "    # Otherwise kick off interviews in parallel via Send() API\n",
    "    else:\n",
    "        topic = state[\"topic\"]\n",
    "        return [Send(\"conduct_interview\", {\"analyst\": analyst,\n",
    "                                           \"messages\": [HumanMessage(\n",
    "                                               content=f\"So you said you were analyzing the {topic} stock?\"\n",
    "                                           )\n",
    "                                                       ]}) for analyst in state[\"analysts\"]]\n",
    "\n",
    "report_writer_instructions = \"\"\"You are a technical writer creating a report on the market trends for the {topic} stock.\n",
    "    \n",
    "You have a team of analysts. Each analyst has done two things: \n",
    "\n",
    "1. They conducted an interview with an expert on a specific sub-topic.\n",
    "2. They write up their finding into a memo.\n",
    "\n",
    "Your task: \n",
    "\n",
    "1. You will be given a collection of memos from your analysts.\n",
    "2. Think carefully about the key insights from each memo.\n",
    "3. Consolidate these into a crisp overall summary that ties together the key ideas from all of the memos. \n",
    "4. Summarize the central points in each memo into a cohesive single narrative.\n",
    "\n",
    "To format your report:\n",
    " \n",
    "1. Use markdown formatting. \n",
    "2. Include no pre-amble for the report.\n",
    "3. Use no sub-heading. \n",
    "4. Start your report with a single title header: ## Insights\n",
    "5. Do not mention any analyst names in your report.\n",
    "6. Preserve any citations in the memos, which will be annotated in brackets, for example [1] or [2].\n",
    "7. Create a final, consolidated list of sources and add to a Sources section with the `## Sources` header.\n",
    "8. List your sources in order and do not repeat.\n",
    "\n",
    "[1] Source 1\n",
    "[2] Source 2\n",
    "\n",
    "Here are the memos from your analysts to build your report from: \n",
    "\n",
    "{context}\"\"\"\n",
    "\n",
    "def write_report(state: ResearchGraphState):\n",
    "    # Full set of sections\n",
    "    sections = state[\"sections\"]\n",
    "    topic = state[\"topic\"]\n",
    "\n",
    "    # Concat all sections together\n",
    "    formatted_str_sections = \"\\n\\n\".join([f\"{section}\" for section in sections])\n",
    "    \n",
    "    # Summarize the sections into a final report\n",
    "    system_message = report_writer_instructions.format(topic=topic, context=formatted_str_sections)    \n",
    "    report = llm.invoke([SystemMessage(content=system_message)]+[HumanMessage(content=f\"Write a report based upon these memos.\")]) \n",
    "    return {\"content\": report.content}\n",
    "\n",
    "intro_conclusion_instructions = \"\"\"You are a technical writer finishing a report on {topic}\n",
    "\n",
    "You will be given all of the sections of the report.\n",
    "\n",
    "You job is to write an effective introduction or conclusion section.\n",
    "\n",
    "The user will instruct you whether to write the introduction or conclusion.\n",
    "\n",
    "Include no pre-amble for either section.\n",
    "\n",
    "Target around 100 words, crisply previewing (for introduction) or recapping (for conclusion) all of the sections of the report.\n",
    "\n",
    "Use markdown formatting. \n",
    "\n",
    "For your introduction, create a compelling title and use the # header for the title.\n",
    "\n",
    "For your introduction, use ## Introduction as the section header. \n",
    "\n",
    "For your conclusion, use ## Conclusion as the section header.\n",
    "\n",
    "Here are the sections to reflect on for writing: {formatted_str_sections}\"\"\"\n",
    "\n",
    "def write_introduction(state: ResearchGraphState):\n",
    "    # Full set of sections\n",
    "    sections = state[\"sections\"]\n",
    "    topic = state[\"topic\"]\n",
    "\n",
    "    # Concat all sections together\n",
    "    formatted_str_sections = \"\\n\\n\".join([f\"{section}\" for section in sections])\n",
    "    \n",
    "    # Summarize the sections into a final report\n",
    "    \n",
    "    instructions = intro_conclusion_instructions.format(topic=topic, formatted_str_sections=formatted_str_sections)    \n",
    "    intro = llm.invoke([instructions]+[HumanMessage(content=f\"Write the report introduction\")]) \n",
    "    return {\"introduction\": intro.content}\n",
    "\n",
    "def write_conclusion(state: ResearchGraphState):\n",
    "    # Full set of sections\n",
    "    sections = state[\"sections\"]\n",
    "    topic = state[\"topic\"]\n",
    "\n",
    "    # Concat all sections together\n",
    "    formatted_str_sections = \"\\n\\n\".join([f\"{section}\" for section in sections])\n",
    "    \n",
    "    # Summarize the sections into a final report\n",
    "    \n",
    "    instructions = intro_conclusion_instructions.format(topic=topic, formatted_str_sections=formatted_str_sections)    \n",
    "    conclusion = llm.invoke([instructions]+[HumanMessage(content=f\"Write the report conclusion\")]) \n",
    "    return {\"conclusion\": conclusion.content}\n",
    "\n",
    "def finalize_report(state: ResearchGraphState):\n",
    "    \"\"\" The is the \"reduce\" step where we gather all the sections, combine them, and reflect on them to write the intro/conclusion \"\"\"\n",
    "    # Save full final report\n",
    "    content = state[\"content\"]\n",
    "    if content.startswith(\"## Insights\"):\n",
    "        content = content.strip(\"## Insights\")\n",
    "    if \"## Sources\" in content:\n",
    "        try:\n",
    "            content, sources = content.split(\"\\n## Sources\\n\")\n",
    "        except:\n",
    "            sources = None\n",
    "    else:\n",
    "        sources = None\n",
    "\n",
    "    final_report = state[\"introduction\"] + \"\\n\\n---\\n\\n\" + content + \"\\n\\n---\\n\\n\" + state[\"conclusion\"]\n",
    "    if sources is not None:\n",
    "        final_report += \"\\n\\n## Sources\\n\" + sources\n",
    "    return {\"final_report\": final_report}\n",
    "\n",
    "# Add nodes and edges \n",
    "builder = StateGraph(ResearchGraphState)\n",
    "builder.add_node(\"create_analysts\", create_analysts)\n",
    "builder.add_node(\"human_feedback\", human_feedback)\n",
    "builder.add_node(\"conduct_interview\", interview_builder.compile())\n",
    "builder.add_node(\"write_report\",write_report)\n",
    "builder.add_node(\"write_introduction\",write_introduction)\n",
    "builder.add_node(\"write_conclusion\",write_conclusion)\n",
    "builder.add_node(\"finalize_report\",finalize_report)\n",
    "\n",
    "# Logic\n",
    "builder.add_edge(START, \"create_analysts\")\n",
    "builder.add_edge(\"create_analysts\", \"human_feedback\")\n",
    "builder.add_conditional_edges(\"human_feedback\", initiate_all_interviews, [\"create_analysts\", \"conduct_interview\"])\n",
    "builder.add_edge(\"conduct_interview\", \"write_report\")\n",
    "builder.add_edge(\"conduct_interview\", \"write_introduction\")\n",
    "builder.add_edge(\"conduct_interview\", \"write_conclusion\")\n",
    "builder.add_edge([\"write_conclusion\", \"write_report\", \"write_introduction\"], \"finalize_report\")\n",
    "builder.add_edge(\"finalize_report\", END)\n",
    "\n",
    "# Compile\n",
    "memory = MemorySaver()\n",
    "graph = builder.compile(interrupt_before=['human_feedback'], checkpointer=memory)\n",
    "display(Image(graph.get_graph(xray=1).draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "362932ee-4106-4a2d-a32d-b812eafcf9df",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Name: Jordan Lee\n",
      "Affiliation: MarketWatch\n",
      "Role: Market Analyst\n",
      "Description: Jordan specializes in analyzing market trends for AAPL using technical indicators such as moving averages, RSI, and MACD. With a keen eye for chart patterns, Jordan provides insights on potential price movements and market entry points.\n",
      "--------------------------------------------------\n",
      "Name: Samantha Chen\n",
      "Affiliation: Sentiment Analysis Group\n",
      "Role: Social Media Sentiment Analyst\n",
      "Description: Samantha focuses on analyzing social media sentiment surrounding AAPL stock. By leveraging natural language processing tools, she gauges public sentiment from platforms like Twitter and Reddit, providing insights into how social trends may impact stock performance.\n",
      "--------------------------------------------------\n",
      "Name: Michael Thompson\n",
      "Affiliation: Global Economic Review\n",
      "Role: News Analyst\n",
      "Description: Michael analyzes global economic trends and news that could affect AAPL's market performance. He monitors economic indicators, geopolitical events, and industry news to provide a comprehensive view of external factors influencing the stock.\n",
      "--------------------------------------------------\n",
      "Name: Emily Rodriguez\n",
      "Affiliation: Financial Insights\n",
      "Role: Fundamentals Analyst\n",
      "Description: Emily evaluates AAPL's financial health by analyzing its earnings reports, balance sheets, and cash flow statements. She focuses on key financial metrics and ratios to assess the company's performance and long-term viability in the market.\n",
      "--------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "# Inputs\n",
    "max_analysts = 4 \n",
    "topic = \"AAPL\"\n",
    "thread = {\"configurable\": {\"thread_id\": \"1\"}}\n",
    "\n",
    "# Run the graph until the first interruption\n",
    "for event in graph.stream({\"topic\":topic,\n",
    "                           \"max_analysts\":max_analysts}, \n",
    "                          thread, \n",
    "                          stream_mode=\"values\"):\n",
    "    \n",
    "    analysts = event.get('analysts', '')\n",
    "    if analysts:\n",
    "        for analyst in analysts:\n",
    "            print(f\"Name: {analyst.name}\")\n",
    "            print(f\"Affiliation: {analyst.affiliation}\")\n",
    "            print(f\"Role: {analyst.role}\")\n",
    "            print(f\"Description: {analyst.description}\")\n",
    "            print(\"-\" * 50)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "ac521a5f-5a4f-44f9-8af9-d05228e20882",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'configurable': {'thread_id': '1',\n",
       "  'checkpoint_ns': '',\n",
       "  'checkpoint_id': '1f00f2cb-d8de-6fd1-8002-c46b6d168ae1'}}"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# We now update the state as if we are the human_feedback node\n",
    "graph.update_state(thread, {\"human_analyst_feedback\": \n",
    "                                \"ensure that the news analyst only uses news from the past three weeks\"}, as_node=\"human_feedback\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "a3be311f-62ee-49e7-b037-75c53d8960a8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Name: Jordan Lee\n",
      "Affiliation: MarketWatch\n",
      "Role: Market Analyst\n",
      "Description: Jordan specializes in analyzing market trends for AAPL using technical indicators such as moving averages, RSI, and MACD. With a keen eye for chart patterns, Jordan provides insights on potential price movements and market entry points.\n",
      "--------------------------------------------------\n",
      "Name: Samantha Chen\n",
      "Affiliation: Sentiment Analysis Group\n",
      "Role: Social Media Sentiment Analyst\n",
      "Description: Samantha focuses on analyzing social media sentiment surrounding AAPL stock. By leveraging natural language processing tools, she gauges public sentiment from platforms like Twitter and Reddit, providing insights into how social trends may impact stock performance.\n",
      "--------------------------------------------------\n",
      "Name: Michael Thompson\n",
      "Affiliation: Global Economic Review\n",
      "Role: News Analyst\n",
      "Description: Michael analyzes global economic trends and news that could affect AAPL's market performance. He monitors economic indicators, geopolitical events, and industry news to provide a comprehensive view of external factors influencing the stock.\n",
      "--------------------------------------------------\n",
      "Name: Emily Rodriguez\n",
      "Affiliation: Financial Insights\n",
      "Role: Fundamentals Analyst\n",
      "Description: Emily evaluates AAPL's financial health by analyzing its earnings reports, balance sheets, and cash flow statements. She focuses on key financial metrics and ratios to assess the company's performance and long-term viability in the market.\n",
      "--------------------------------------------------\n",
      "Name: Jordan Lee\n",
      "Affiliation: MarketWatch\n",
      "Role: Market Analyst\n",
      "Description: Jordan specializes in analyzing market trends for AAPL using technical indicators such as moving averages, RSI, and MACD. With a focus on short-term price movements, Jordan provides insights into potential entry and exit points for traders.\n",
      "--------------------------------------------------\n",
      "Name: Emily Chen\n",
      "Affiliation: Sentiment Tracker\n",
      "Role: Social Media Sentiment Analyst\n",
      "Description: Emily monitors social media platforms to gauge public sentiment around AAPL. By analyzing tweets, posts, and comments, she identifies trends in consumer perception and investor sentiment, providing a unique perspective on market movements.\n",
      "--------------------------------------------------\n",
      "Name: Michael Thompson\n",
      "Affiliation: Global Economic Review\n",
      "Role: News Analyst\n",
      "Description: Michael focuses on analyzing recent global economic news that impacts AAPL. He reviews articles and reports from the past three weeks to assess how geopolitical events, economic data releases, and industry news influence AAPL's stock performance.\n",
      "--------------------------------------------------\n",
      "Name: Sarah Patel\n",
      "Affiliation: Financial Insights Group\n",
      "Role: Fundamentals Analyst\n",
      "Description: Sarah evaluates AAPL's financial health by analyzing quarterly earnings reports, revenue growth, profit margins, and other key financial metrics. Her focus is on long-term investment potential and the overall stability of the company.\n",
      "--------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "# Check\n",
    "for event in graph.stream(None, thread, stream_mode=\"values\"):\n",
    "    analysts = event.get('analysts', '')\n",
    "    if analysts:\n",
    "        for analyst in analysts:\n",
    "            print(f\"Name: {analyst.name}\")\n",
    "            print(f\"Affiliation: {analyst.affiliation}\")\n",
    "            print(f\"Role: {analyst.role}\")\n",
    "            print(f\"Description: {analyst.description}\")\n",
    "            print(\"-\" * 50)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "0af41f54-88d9-4597-98b0-444c08322095",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'configurable': {'thread_id': '1',\n",
       "  'checkpoint_ns': '',\n",
       "  'checkpoint_id': '1f00f2cb-f90c-6558-8004-8668aa1b9f3f'}}"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Confirm we are happy\n",
    "graph.update_state(thread, {\"human_analyst_feedback\": \n",
    "                            None}, as_node=\"human_feedback\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "37123ca7-c20b-43c1-9a71-39ba344e7ca6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--Node--\n",
      "conduct_interview\n",
      "--Node--\n",
      "conduct_interview\n",
      "--Node--\n",
      "conduct_interview\n",
      "--Node--\n",
      "conduct_interview\n",
      "--Node--\n",
      "write_introduction\n",
      "--Node--\n",
      "write_conclusion\n",
      "--Node--\n",
      "write_report\n",
      "--Node--\n",
      "finalize_report\n"
     ]
    }
   ],
   "source": [
    "# Continue\n",
    "for event in graph.stream(None, thread, stream_mode=\"updates\"):\n",
    "    print(\"--Node--\")\n",
    "    node_name = next(iter(event.keys()))\n",
    "    print(node_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "f8f66ad8-80fd-4eb2-96b6-6ae9dffd060c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "# Navigating the Landscape of Apple Inc. (AAPL)\n",
       "\n",
       "## Introduction\n",
       "\n",
       "This report provides a comprehensive analysis of Apple Inc. (AAPL), focusing on its current market performance, public sentiment, global economic influences, and financial health. We begin by examining technical indicators and market trends, revealing a mixed performance and cautious trading outlook. Next, we delve into public sentiment analysis, highlighting its significant correlation with stock price movements. The report also evaluates the impact of global economic trends, particularly geopolitical tensions and consumer spending shifts, on AAPL's performance. Finally, we assess Apple's financial health through recent earnings reports, showcasing its resilience and growth potential in a challenging environment.\n",
       "\n",
       "---\n",
       "\n",
       "\n",
       "Apple Inc. (AAPL) is currently navigating a complex market landscape characterized by mixed technical indicators, public sentiment, global economic trends, and its financial health. \n",
       "\n",
       "From a technical analysis perspective, AAPL has shown a neutral performance, with an average trading volume of around 50 million shares per day. The stock is trading within the middle of its 52-week range, reflecting a lack of clear direction. Recent technical ratings score AAPL at 6 out of 10, with bearish indicators such as a MACD of -0.69 and an RSI of 50.71, suggesting potential downward momentum. Traders are advised to consider entry points around $220, with a target price of approximately $223.85, while remaining cautious of a possible decline below this level, which could prompt short positions [1][2][3][4][5][6].\n",
       "\n",
       "Public sentiment analysis reveals that AAPL maintains a positive sentiment score of 68 out of 100, outperforming many industry peers. This sentiment is closely correlated with stock price movements, as demonstrated by machine learning models that predict stock trends based on social media sentiment. The integration of sentiment analysis with traditional financial metrics enhances the accuracy of stock valuation models, providing actionable insights for trading strategies and marketing effectiveness [1][2][3][4][5][6].\n",
       "\n",
       "On a broader scale, global economic trends, particularly geopolitical tensions and fluctuations in exchange rates, are impacting AAPL's market performance. The ongoing conflict in the Middle East has raised concerns about market stability, contributing to a decline in stock performance across various sectors, including technology. AAPL's business is vulnerable to such disruptions, which can adversely affect its supply chain and customer demand. Additionally, the resumption of student loan repayments may divert consumer spending away from discretionary technology purchases, further impacting sales [1][2][3][4][5][6].\n",
       "\n",
       "Despite these challenges, AAPL's financial health remains robust, as evidenced by its recent fiscal fourth-quarter results, which reported a revenue increase of 6% year-over-year and a diluted EPS rise of 12%. The company's diverse product lineup, including the iPhone 16 and Apple Watch Series 10, along with a growing services segment, has contributed to sustained revenue growth. Analysts project a modest growth trajectory for AAPL, with earnings expected to grow at an annual rate of approximately 10.48%. The company's commitment to innovation, reflected in its substantial R&D investment, positions it well for long-term stability and competitiveness in the technology sector [1][2][3][4][5].\n",
       "\n",
       "In conclusion, while AAPL faces a challenging market environment influenced by technical indicators, public sentiment, and global economic factors, its strong financial performance and strategic initiatives suggest a stable outlook for investors. \n",
       "\n",
       "\n",
       "---\n",
       "\n",
       "## Conclusion\n",
       "\n",
       "In summary, Apple Inc. (AAPL) is navigating a complex landscape characterized by mixed technical indicators, public sentiment, global economic trends, and robust financial health. Recent technical analysis suggests a cautious trading environment, with AAPL's stock showing neutral trends and potential bearish signals. Public sentiment remains positive, indicating strong consumer perception, while geopolitical tensions and economic fluctuations pose risks to market stability. Despite challenges in hardware sales, Apple's financial performance remains solid, driven by growth in its services segment and significant operating cash flow. As investors assess these factors, a vigilant approach is essential for navigating AAPL's future stock performance.\n",
       "\n",
       "## Sources\n",
       "[1] https://www.chartmill.com/stock/quote/AAPL/technical-analysis  \n",
       "[2] https://www.tradingview.com/symbols/NASDAQ-AAPL/technicals/  \n",
       "[3] https://www.investtech.com/main/market.php?CompanyID=10503307  \n",
       "[4] https://www.statmuse.com/money/ask?q=apple+stock+as+17th+october%2C+2023  \n",
       "[5] https://www.sec.gov/Archives/edgar/data/320193/000032019323000106/aapl-20230930.htm  \n",
       "[6] https://www.tradingview.com/symbols/NASDAQ-AAPL/ideas//page-17/  \n",
       "[7] https://altindex.com/ticker/aapl/sentiment  \n",
       "[8] https://github.com/you915/Sentiment-Analysis-of-Twitter-Data-for-predicting-Apple-stock-price  \n",
       "[9] https://www.getfocal.co/post/sentiment-analysis-for-stock-valuation-guide  \n",
       "[10] https://medium.com/funny-ai-quant/sentiment-analysis-in-trading-an-in-depth-guide-to-implementation-b212a1df8391  \n",
       "[11] https://sproutsocial.com/insights/social-media-sentiment-analysis/  \n",
       "[12] https://www.researchgate.net/publication/282298117_Sentiment_Analysis_on_Social_Media_for_Stock_Movement_Prediction  \n",
       "[13] https://www.fandc.com/insights/market-snapshot-october-2023/  \n",
       "[14] https://permutable.ai/understanding-the-influential-factors-behind-apple-inc-stock-price/  \n",
       "[15] https://finance.yahoo.com/news/why-apple-aapl-fell-q3-103754682.html  \n",
       "[16] https://students.tippie.uiowa.edu/sites/students.tippie.uiowa.edu/files/2023-11/f23_AAPL.pdf  \n",
       "[17] https://www.cnbc.com/2023/12/29/apple-underperformed-mega-cap-peers-in-2023-due-to-revenue-slide.html  \n",
       "[18] https://www.apple.com/newsroom/2024/10/apple-reports-fourth-quarter-results/  \n",
       "[19] https://simplywall.st/stocks/us/tech/nasdaq-aapl/apple  \n",
       "[20] https://www.morningstar.com/stocks/after-earnings-is-apple-stock-buy-sell-or-fairly-valued-6  \n",
       "[21] https://www.ainvest.com/news/apple-stock-surges-30-in-2024-a-closer-look-at-factors-behind-gains-250110105f76668b70d65e15/  \n",
       "[22] https://www.forbes.com/sites/investor-hub/article/where-will-apple-aapl-stock-be-in-5-years/"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.display import Markdown\n",
    "final_state = graph.get_state(thread)\n",
    "report = final_state.values.get('final_report')\n",
    "Markdown(report)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d0b1723d-c101-4a8e-abcd-9d25b0a54c1f",
   "metadata": {},
   "source": [
    "## Researcher Team: Debating Agents\n",
    "* Generate Researchers (we make them a type of Analyst)\n",
    "* Make them debate (using interview logic)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "60bbea61-d582-4577-94fa-7a4d8d8e8426",
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import Optional\n",
    "\n",
    "class DebateState(TypedDict):\n",
    "    topic: str\n",
    "    report: str\n",
    "    max_rounds: int\n",
    "    round_num: int\n",
    "    transcript: str\n",
    "    bullish_analyst: Analyst\n",
    "    bearish_analyst: Analyst\n",
    "    bullish_argument: Optional[str]\n",
    "    bearish_argument: Optional[str]\n",
    "    final_decision: str"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "736a4240-95fd-45cd-8e83-79c6ddb54897",
   "metadata": {},
   "outputs": [],
   "source": [
    "def generate_initial_argument(state: DebateState):\n",
    "    \"\"\"Each analyst reads the report and builds an initial argument.\"\"\"\n",
    "    report = state[\"report\"]\n",
    "    bullish = state[\"bullish_analyst\"]\n",
    "    bearish = state[\"bearish_analyst\"]\n",
    "\n",
    "    # Get initial arguments\n",
    "    bullish_argument = llm.invoke([\n",
    "        SystemMessage(content=f\"You are {bullish.persona}. Read this stock report and provide a bullish argument that is 150 words max:\"),\n",
    "        HumanMessage(content=report)\n",
    "    ]).content\n",
    "\n",
    "    bearish_argument = llm.invoke([\n",
    "        SystemMessage(content=f\"You are {bearish.persona}. Read this stock report and provide a bearish argument that is 150 words max:\"),\n",
    "        HumanMessage(content=report)\n",
    "    ]).content\n",
    "\n",
    "    return {\n",
    "        \"bullish_argument\": bullish_argument,\n",
    "        \"bearish_argument\": bearish_argument,\n",
    "        \"round_num\": 1,\n",
    "        \"transcript\": f\"**Round 1:**\\nBullish: {bullish_argument}\\nBearish: {bearish_argument}\\n\\n\"\n",
    "    }\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "a28d6806-f3fd-4e8d-a487-5f8a83b53b22",
   "metadata": {},
   "outputs": [],
   "source": [
    "def debate_round(state: DebateState):\n",
    "    \"\"\"Each researcher rebuts the previous argument.\"\"\"\n",
    "    round_num = state[\"round_num\"]\n",
    "    bullish_argument = state[\"bullish_argument\"]\n",
    "    bearish_argument = state[\"bearish_argument\"]\n",
    "    transcript = state[\"transcript\"]\n",
    "\n",
    "    # Generate rebuttals (one API call each)\n",
    "    bullish_rebuttal = llm.invoke([\n",
    "        SystemMessage(content=\"You are a bullish analyst. Rebut the following bearish argument in 70 words max:\"),\n",
    "        HumanMessage(content=bearish_argument)\n",
    "    ]).content\n",
    "\n",
    "    bearish_rebuttal = llm.invoke([\n",
    "        SystemMessage(content=\"You are a bearish analyst. Rebut the following bullish argument in 70 words max:\"),\n",
    "        HumanMessage(content=bullish_argument)\n",
    "    ]).content\n",
    "\n",
    "    # Append to transcript\n",
    "    transcript += f\"**Round {round_num+1}:**\\nBullish: {bullish_rebuttal}\\nBearish: {bearish_rebuttal}\\n\\n\"\n",
    "\n",
    "    return {\n",
    "        \"bullish_argument\": bullish_rebuttal,\n",
    "        \"bearish_argument\": bearish_rebuttal,\n",
    "        \"round_num\": round_num + 1,\n",
    "        \"transcript\": transcript\n",
    "    }\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "06c589ff-fcfe-479b-9edc-477eb2035d50",
   "metadata": {},
   "outputs": [],
   "source": [
    "def trader_decision(state: DebateState):\n",
    "    \"\"\"Trader makes a final decision based on the debate transcript.\"\"\"\n",
    "    transcript = state[\"transcript\"]\n",
    "\n",
    "    decision = llm.invoke([\n",
    "        SystemMessage(content=\"You are a trader making a stock decision.\"),\n",
    "        HumanMessage(content=f\"Here is a debate transcript about the stock:\\n\\n{transcript}\\n\\nShould you BUY, SELL, or HOLD? Provide reasoning. Keep response to a maximum of 200 words.\")\n",
    "    ]).content\n",
    "\n",
    "    return {\"final_decision\": decision}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "b40a0966-dc73-4f20-b3f0-8a394d7376b1",
   "metadata": {},
   "outputs": [],
   "source": [
    "def should_continue(state: DebateState):\n",
    "    \"\"\"Controls whether to continue the debate or move to trader decision.\"\"\"\n",
    "    max_rounds = state.get(\"max_rounds\", 3)  # User-defined max rounds\n",
    "    return \"debate_round\" if state[\"round_num\"] < max_rounds else \"trader_decision\"\n",
    "\n",
    "graph = StateGraph(DebateState)\n",
    "\n",
    "# Add nodes\n",
    "graph.add_node(\"generate_initial_argument\", generate_initial_argument)\n",
    "graph.add_node(\"debate_round\", debate_round)\n",
    "graph.add_node(\"trader_decision\", trader_decision)\n",
    "\n",
    "# Start with initial arguments\n",
    "graph.set_entry_point(\"generate_initial_argument\")\n",
    "\n",
    "# Debate 1-5 rounds before moving to trader decision\n",
    "graph.add_edge(\"generate_initial_argument\", \"debate_round\")\n",
    "graph.add_conditional_edges(\"debate_round\", should_continue, [\"debate_round\", \"trader_decision\"])\n",
    "\n",
    "# Final output\n",
    "graph.set_finish_point(\"trader_decision\")\n",
    "\n",
    "# Compile the graph\n",
    "pipeline = graph.compile()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "a8682ecc-5eca-40ec-9670-104fe03f8475",
   "metadata": {},
   "outputs": [],
   "source": [
    "topic = \"AAPL\"\n",
    "max_rounds = 3  # Set between 1-5\n",
    "\n",
    "initial_state = {\n",
    "    \"topic\": topic,\n",
    "    \"report\": report,\n",
    "    \"max_rounds\": max_rounds,\n",
    "    \"bullish_analyst\": Analyst(\n",
    "        affiliation=\"Stock Market Analysts Inc.\",\n",
    "        name=\"Bullish Researcher\",\n",
    "        role=\"Bullish\",\n",
    "        description=f\"Believes {topic} stock will increase in value and argues in favor of buying.\"\n",
    "    ),\n",
    "    \"bearish_analyst\": Analyst(\n",
    "        affiliation=\"Hedge Fund Analysts\",\n",
    "        name=\"Bearish Researcher\",\n",
    "        role=\"Bearish\",\n",
    "        description=f\"Believes {topic} stock will decrease in value and argues in favor of selling.\"\n",
    "    ),\n",
    "}\n",
    "\n",
    "debate_result = pipeline.invoke(initial_state)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "78a755c7-d43b-4a55-9583-627820cee71d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "**Round 1:**\n",
       "Bullish: Apple Inc. (AAPL) presents a compelling investment opportunity despite current market challenges. The company's recent fiscal fourth-quarter results showcased a 6% year-over-year revenue increase and a 12% rise in diluted EPS, underscoring its financial resilience. With a robust product lineup, including the iPhone 16 and Apple Watch Series 10, coupled with a rapidly growing services segment, AAPL is well-positioned for sustained growth.\n",
       "\n",
       "Moreover, public sentiment remains strong, with a score of 68 out of 100, indicating positive consumer perception that often correlates with stock price appreciation. Analysts project earnings growth at approximately 10.48% annually, reflecting confidence in Apple's innovative capabilities and strategic investments in R&D.\n",
       "\n",
       "While geopolitical tensions and economic fluctuations pose risks, AAPL's strong fundamentals and commitment to innovation suggest a stable outlook. This makes AAPL a prime candidate for investors looking to capitalize on long-term growth potential in the technology sector.\n",
       "Bearish: Apple Inc. (AAPL) is facing significant headwinds that suggest a bearish outlook for its stock. Despite a positive sentiment score, the technical indicators reveal a concerning trend, with a MACD of -0.69 and an RSI of 50.71, indicating potential downward momentum. The stock is trading in the middle of its 52-week range, reflecting uncertainty and lack of clear direction.\n",
       "\n",
       "Moreover, global economic factors, including geopolitical tensions and the resumption of student loan repayments, threaten consumer spending on discretionary items like technology. This could lead to a decline in AAPL's sales, particularly in its hardware segment, which has already shown signs of weakness. \n",
       "\n",
       "While the company reports solid financials, the modest growth projections of 10.48% may not justify its current valuation, especially in a volatile market. Investors should consider selling AAPL to mitigate potential losses as these challenges could lead to a significant decline in stock value.\n",
       "\n",
       "**Round 2:**\n",
       "Bullish: While concerns exist, Apple’s strong brand loyalty and ecosystem provide resilience against economic headwinds. The company consistently innovates, with upcoming product launches likely to drive sales. Additionally, its services segment is growing rapidly, offsetting hardware weaknesses. AAPL's solid financials and a 10.48% growth projection, while modest, are still robust in a volatile market. Selling now could mean missing out on potential gains as Apple adapts and thrives in changing conditions.\n",
       "Bearish: While Apple’s recent revenue and EPS growth appear positive, these figures may mask underlying issues such as market saturation and declining iPhone sales. The reliance on a few flagship products raises concerns about long-term sustainability. Additionally, the projected earnings growth of 10.48% may be overly optimistic given economic uncertainties and rising competition. Public sentiment can shift quickly, and geopolitical tensions could further impact consumer spending, making AAPL a risky investment.\n",
       "\n",
       "**Round 3:**\n",
       "Bullish: Apple's strong brand loyalty and ecosystem mitigate market saturation risks, while ongoing innovation in services and wearables diversifies revenue streams. The projected earnings growth reflects robust demand for new products and services, not just iPhones. Economic uncertainties are present, but Apple's financial strength and adaptability position it well to navigate challenges. Moreover, geopolitical tensions often create buying opportunities for resilient companies like Apple, making it a compelling long-term investment.\n",
       "Bearish: Brand loyalty and ecosystem strength may not shield Apple from macroeconomic pressures, especially as consumer spending tightens. Innovation is uncertain; past successes don't guarantee future performance. The services segment, while growing, may not compensate for declining hardware sales. AAPL's growth projection, though positive, is modest and could be overly optimistic in a volatile market. Selling now could mitigate losses rather than risk further declines as economic conditions worsen.\n",
       "\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#print result\n",
    "Markdown(debate_result[\"transcript\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "b2e7e26c-8912-4821-b328-795e996e52b8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "Based on the debate, I would recommend a **HOLD** position on Apple Inc. (AAPL). The bullish arguments highlight Apple's strong financial performance, brand loyalty, and growth in its services segment, which are compelling factors for long-term investment. The projected earnings growth of 10.48% suggests potential for continued profitability.\n",
       "\n",
       "However, the bearish perspective raises valid concerns about market saturation, reliance on flagship products, and external economic pressures that could impact consumer spending. The technical indicators, such as the MACD and RSI, indicate potential downward momentum, suggesting caution.\n",
       "\n",
       "Given the mixed signals—strong fundamentals versus economic uncertainties—holding AAPL allows for monitoring its performance and market conditions without committing to a buy or sell decision. This strategy provides time to assess how Apple navigates upcoming challenges and capitalizes on its innovation and brand strength."
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#print trader's decision\n",
    "Markdown(debate_result[\"final_decision\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1573051f-28ee-478a-a241-d16a630a78f4",
   "metadata": {},
   "source": [
    "## Risk and Fund Management\n",
    "* Two agents, one for risk, one for funds\n",
    "* The Risk agent gives a range + places qualifiers on the trader's decision\n",
    "* The Fund agent finalizes the amount to buy/sell based on available funds (user input)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "da33cb47-0a01-475d-8282-8a841a6b3290",
   "metadata": {},
   "source": [
    "### Risk Agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "4bb86b9d-611f-4966-9924-1d62ec242c30",
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import TypedDict, Optional, Dict, Any\n",
    "\n",
    "class RiskState(TypedDict):\n",
    "    decision: str\n",
    "    topic: str\n",
    "    data: Dict[str, Any]\n",
    "    #output vars\n",
    "    risk_decision: Optional[str]\n",
    "    fund_pct_cap: Optional[float]\n",
    "    risk_level: Optional[str]\n",
    "    risk_logs: Optional[str]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "09257d3e-848c-4b00-bbf4-32017b01d0d4",
   "metadata": {},
   "outputs": [],
   "source": [
    "import re\n",
    "\n",
    "def extract_action_from_text(text: str) -> str:\n",
    "    \"\"\"Extract BUY, SELL, or HOLD from the trader's final decision text.\"\"\"\n",
    "    match = re.search(r\"\\b(BUY|SELL|HOLD)\\b\", text.upper())\n",
    "    return match.group(1) if match else \"HOLD\"\n",
    "\n",
    "def risk_manager(state: RiskState) -> dict:\n",
    "    decision = state.get(\"final_decision\", \"\")\n",
    "    data = state.get(\"market_data\", {})\n",
    "\n",
    "    action = extract_action_from_text(decision)\n",
    "\n",
    "    # Pull market stats\n",
    "    bb = data.get(\"bollinger_band_width\", 0.15)\n",
    "    vix = data.get(\"vix\", 20)\n",
    "\n",
    "    # Risk assessment\n",
    "    if bb > 0.2 or vix > 25:\n",
    "        risk_label = \"High\"\n",
    "        max_pct = 0.03\n",
    "    elif bb > 0.1 or vix > 20:\n",
    "        risk_label = \"Moderate\"\n",
    "        max_pct = 0.05\n",
    "    else:\n",
    "        risk_label = \"Low\"\n",
    "        max_pct = 0.07\n",
    "\n",
    "    if action == \"HOLD\":\n",
    "        max_pct = 0.0\n",
    "\n",
    "    return {\n",
    "        \"risk_decision\": action,\n",
    "        \"fund_pct_cap\": max_pct,\n",
    "        \"risk_level\": risk_label,\n",
    "        \"risk_logs\": f\"BB width: {bb}, VIX: {vix}, assessed as {risk_label} risk\"\n",
    "    }\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "538645ea-58f2-4768-85ac-555a87792a17",
   "metadata": {},
   "outputs": [],
   "source": [
    "risk_graph = StateGraph(RiskState)\n",
    "\n",
    "# Add nodes\n",
    "\n",
    "risk_graph.add_node(\"risk_manager\", risk_manager)\n",
    "risk_graph.set_entry_point(\"risk_manager\")\n",
    "risk_graph.set_finish_point(\"risk_manager\")\n",
    "\n",
    "# Compile the graph\n",
    "risk_pipeline = risk_graph.compile()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "4f18a3c2-a47a-4e93-8221-13c56d93a72c",
   "metadata": {},
   "outputs": [],
   "source": [
    "#USING DUMMY VARS FOR DATA FOR NOW\n",
    "#LATER USE TAVILY TO GET ACTUAL DATA\n",
    "risk_input: RiskState = {\n",
    "    \"decision\": debate_result[\"final_decision\"],\n",
    "    \"topic\": debate_result[\"topic\"],\n",
    "    \"data\": {\n",
    "        \"bollinger_band_width\": 0.15,\n",
    "        \"vix\": 22,\n",
    "        \"stock_price\": 171.43,\n",
    "        \"beta\": 1.3\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "7180c77e-cdc2-411d-bc20-837514fa7ea9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Risk Decision: HOLD\n",
      "Fund Use % Cap: 0.0\n",
      "Risk Level: Moderate\n",
      "Logs: BB width: 0.15, VIX: 20, assessed as Moderate risk\n"
     ]
    }
   ],
   "source": [
    "risk_result = risk_pipeline.invoke(risk_input)\n",
    "\n",
    "print(\"Risk Decision:\", risk_result[\"risk_decision\"])\n",
    "print(\"Fund Use % Cap:\", risk_result[\"fund_pct_cap\"])\n",
    "print(\"Risk Level:\", risk_result[\"risk_level\"])\n",
    "print(\"Logs:\", risk_result[\"risk_logs\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7e88f2d5-caaf-4c04-80c4-6e7697f0c021",
   "metadata": {},
   "source": [
    "### Fund Agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "2ea74e5f-abe9-41d9-adc0-9ec230f3b46a",
   "metadata": {},
   "outputs": [],
   "source": [
    "class FundState(TypedDict):\n",
    "    fund_cash: float\n",
    "    fund_value: float\n",
    "\n",
    "    final_action: Optional[str]\n",
    "    shares_to_trade: Optional[int]\n",
    "    dollar_amount: Optional[float]\n",
    "    fund_notes: Optional[str]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "740b6dc8-efd2-4462-9267-db1874684400",
   "metadata": {},
   "outputs": [],
   "source": [
    "def fund_manager(state: FundState) -> dict:\n",
    "    action = risk_result[\"risk_decision\"]\n",
    "    max_pct = risk_result[\"fund_pct_cap\"]\n",
    "    market_data = risk_result[\"data\"]\n",
    "    cash = state[\"fund_cash\"]\n",
    "    fund_value = state[\"fund_value\"]\n",
    "\n",
    "    stock_price = market_data.get(\"stock_price\", 0)\n",
    "\n",
    "    max_dollar_allocation = fund_value * max_pct\n",
    "    allowable_cash = min(max_dollar_allocation, cash)\n",
    "\n",
    "    if action == \"HOLD\" or stock_price == 0 or allowable_cash < stock_price:\n",
    "        return {\n",
    "            \"final_action\": \"HOLD\",\n",
    "            \"shares_to_trade\": 0,\n",
    "            \"dollar_amount\": 0,\n",
    "            \"fund_notes\": \"No trade made due to HOLD or low funds.\"\n",
    "        }\n",
    "\n",
    "    num_shares = int(allowable_cash // stock_price)\n",
    "    trade_value = num_shares * stock_price\n",
    "\n",
    "    return {\n",
    "        \"final_action\": action,\n",
    "        \"shares_to_trade\": num_shares,\n",
    "        \"dollar_amount\": trade_value,\n",
    "        \"fund_notes\": f\"{action} {num_shares} shares at ${stock_price:.2f}, totaling ${trade_value:.2f}.\"\n",
    "    }\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "id": "c26ab479-e508-400d-8b65-20d5b2b68c0d",
   "metadata": {},
   "outputs": [],
   "source": [
    "fund_graph = StateGraph(FundState)\n",
    "\n",
    "fund_graph.add_node(\"fund_manager\", fund_manager)\n",
    "fund_graph.set_entry_point(\"fund_manager\")\n",
    "fund_graph.set_finish_point(\"fund_manager\")\n",
    "\n",
    "fund_pipeline = fund_graph.compile()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "id": "2aaf64aa-8d49-4613-aa87-03c550cb17c2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "HOLD\n",
      "0\n",
      "0\n",
      "No trade made due to HOLD or low funds.\n"
     ]
    }
   ],
   "source": [
    "#USER INPUT HERE - CASH and VALUE of funds\n",
    "#TO DO - make this an interactable component\n",
    "#so that the pipeline breaks and asks for user input before continuing\n",
    "fund_input: FundState = {\n",
    "    \"fund_cash\": 5000.0,\n",
    "    \"fund_value\": 10000.0\n",
    "}\n",
    "\n",
    "fund_result = fund_pipeline.invoke(fund_input)\n",
    "\n",
    "print(fund_result[\"final_action\"])\n",
    "print(fund_result[\"shares_to_trade\"])\n",
    "print(fund_result[\"dollar_amount\"])\n",
    "print(fund_result[\"fund_notes\"])\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
